from rest_framework import serializers
from home.models import AxfUser
from django.contrib.auth.hashers import make_password,check_password


class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model=AxfUser
        fields='__all__'


class UserRegisterSerializer(serializers.Serializer): # 用户注册用的序列化类。继承自Serializer类时可以完全自定义
    u_username=serializers.CharField(required=True) # required设为True表示必传该项
    u_password=serializers.CharField(min_length=6,max_length=18,error_messages={'max_length':'最大长度不超过18位','min_length':'最小长度不少于6位'}) # error_messages的格式在CharField()中
    u_password2=serializers.CharField(min_length=6,max_length=18,error_messages={'max_length':'最大长度不超过18位','min_length':'最小长度不少于6位'}) # 确认密码
    u_email=serializers.EmailField(required=True)

    def validate_u_username(self,value): # 验证用户名是否唯一。对单个字段验证，下划线后是要验证的字段名，一个字段写一个方法，当前方法内不能验证其他字段
        if AxfUser.objects.filter(u_username=value).first():
            raise serializers.ValidationError({'username':'该用户名已被使用，请更换用户名'}) # 错误信息写成字典，方便查看，否则返回的报错信息中键的地方显示non_field_errors(不影响查看报错信息)，写成字典后键的地方显示字典的键名
        return value

    def validate_u_email(self,value): # 验证邮箱是否唯一
        if AxfUser.objects.filter(u_email=value).first():
            raise serializers.ValidationError({'email': '该邮箱已被使用，请更换邮箱'})
        return value

    def validate(self, attrs): # 验证两次输入的密码是否一致。对多个字段验证，有单个验证时，需写在单个验证的方法的后面，因先执行单个字段验证，再执行多个字段验证
        password=attrs['u_password'] # attrs是OrderedDict，是一种字典，中括号和get()两种获取值的方式
        password2=attrs.get('u_password2')
        if password!=password2:
            raise serializers.ValidationError({'password':'两次输入的密码不一致'})
        return attrs

    def create(self, validated_data): # 保存通过验证的数据。不能直接保存接收到的数据(即user/views.py中UserRegisterView类中serializer.save())，因为接收到了u_password2，但数据库中没有u_password2字段。重写父类Serializer的父类BaseSerializer的create()方法，创建新对象时serializer.save()调用这里重写后的create()方法，详细看user/views.py中UserRegisterView类中serializer.save()处注释
        user=AxfUser()
        user.u_username=validated_data['u_username']
        password=validated_data.get('u_password')
        user.u_password=make_password(password) # 对密码加密
        user.u_email=validated_data.get('u_email')
        user.is_active=1 # 模型中未设置默认值，所以创建用户时要赋值
        user.is_delete=0 # 同上一行
        user.save()
        return user # user/views.py中UserRegisterView类中serializer.save()调用这里的create()方法，那里的返回值中需要用到新创建的用户的id，所以这里返回新创建的用户


class UserLoginSerializer(serializers.Serializer): # 用户登录用的序列化类，不能继承自serializers.ModelSerializer类，它实现了create()方法，登录时会将用户信息再次存入数据库，而由于是登录，数据库中已有该用户，且用户名唯一，所以再次存入数据库时因用户名重复而报错
    u_username=serializers.CharField(required=True)
    u_password=serializers.CharField(min_length=6)

    def validate(self, attrs):
        username=attrs['u_username']
        password=attrs['u_password']
        user=AxfUser.objects.filter(u_username=username)
        if not user.exists(): # exists()方法判断查询结果集QuerySet中是否有数据，即是否查到了数据，是返回True，否返回False。上一行最后也可以加.first()，那样的话这里不用加.exists()
            raise serializers.ValidationError({'error':'用户名不存在'}) # 最好提示'用户名或密码错误'，防止确认用户名正确后暴破密码。现在这样写是方便测试那些登录失败的判断是否生效
        user=user.first() # 用户名唯一，所以可以从查询结果集中取第一个
        if not check_password(password,user.u_password): # 第一个参数是前端输入的密码，第二个参数是数据库中正确的密码，密码正确返回True，密码错误返回False
            raise serializers.ValidationError({'error':'用户名或密码错误'}) # 实际是密码错误
        return attrs